package br.edu.flf.controle;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import nk.Arvore;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.Syntax;
import com.hp.hpl.jena.sparql.core.TriplePath;
import com.hp.hpl.jena.sparql.syntax.ElementGroup;
import com.hp.hpl.jena.sparql.syntax.ElementOptional;
import com.hp.hpl.jena.sparql.syntax.ElementPathBlock;
import com.hp.hpl.jena.sparql.syntax.ElementUnion;
import com.hp.hpl.jena.sparql.syntax.ElementVisitorBase;
import com.hp.hpl.jena.sparql.syntax.ElementWalker;

public class Converte {

	static Map<Integer, Object> lista = new HashMap<Integer, Object>();
	static int cont = 0;
	static int keyAND = 0;
	static int filhoAND = 0;

	public void adiciona(Object obj) {

		cont++;
		if (obj.equals("AND")) {
			keyAND = cont;
			filhoAND = 2;
			lista.put(cont, obj);
			return;
		}
		// Organiza o and na fila para que este seja pai dos BGPs que pertencem
		// a ele
		if (((filhoAND > 0) && (keyAND > 0) && (cont >= keyAND))
				&& !obj.equals("OPTIONAL") && !obj.equals("UNION")) {

			lista.remove("AND");
			lista.put(keyAND, obj);
			lista.put(keyAND + 1, "AND");
			keyAND = cont;
			filhoAND--;

		} else {
			lista.put(cont, obj);
		}

	}

	public List<String> organiza(Map<Integer, Object> list) {

		List<String> pai = new ArrayList();

		for (int i = list.size(); i >= 1; i--) {
			pai.add(list.get(i).toString());

		}

		return pai;

	}

	/*final String queryString = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>"
			+ "PREFIX s: <http://swrc.ontoware.org/ontology/portal#>"
			+ " SELECT distinct ?p"
			+ " FROM <Semiport.owl>"
			+ " WHERE"
			+ " { "
			+ "{?p rdf:type s:UndergraduateStudent}"
			+ " UNION"
			+ " {?p rdf:type s:AssistantProfessor}"
			+ " UNION"
			+ " {?p rdf:type s:AssistantProfessor2}" 
			+ " }";
			*/			

	public List<String> processaConsulta(String queryString) {

		Query query = QueryFactory.create(queryString, Syntax.syntaxSPARQL_11);
		final ElementGroup elp = (ElementGroup) query.getQueryPattern();

		// final Set<Node> subjects = new HashSet<Node>();

		// This will walk through all parts of the query
		ElementWalker.walk(query.getQueryPattern(),
		// For each element...
				new ElementVisitorBase() {
					// ...when it's a block of triples...

					public void visit(ElementUnion el) {
//						System.out.println("-ElementUnion");
						adiciona("UNION");
					}

					public void visit(ElementOptional el) {
//						System.out.println("-ElementOptional");
						adiciona("OPTIONAL");
					}

					public void visit(ElementPathBlock el) {
						String and = el.getPattern().toString();

						if (and.contains(", ")) {
							adiciona("AND");
						}
//						System.out.println("-ElementPathBlock");
						ElementPathBlock elCopy = new ElementPathBlock();
						Iterator<TriplePath> triples = el.patternElts();

						while (triples.hasNext()) {
							TriplePath t = triples.next();
//							System.out.println(t.getObject());
							adiciona(t.getObject());

						}

						el = elCopy;
					}

				});

		StringBuilder retorno = new StringBuilder();
		retorno.append(lista + "\n");
		System.out.println(lista);

		List<String> arv = organiza(lista);
		List<String> arvOnlyText = new ArrayList<String>();
		for (int i = 0; i < arv.size(); i++) {
			arvOnlyText.add(arv.get(i).replaceAll("[?]", ""));			
		}
		System.out.println(">>>>>>>>>>>>>>>" + arv);
		
		
		
		int fechar = 0;
		int fecharAND = 0;
		for (int i = 0; i < arv.size(); i++) {
			if (arv.get(i).equals("AND")) {
				fecharAND = 1;
			}
			if (arv.get(i).equals("UNION") || arv.get(i).equals("OPTIONAL")
					|| arv.get(i).equals("AND")) {
				if ((fecharAND == 1)
						&& (arv.get(i).equals("UNION") || arv.get(i).equals("OPTIONAL"))) {
					System.out.print(") ");
					retorno.append(") ");
					fecharAND = 0;
				}
				System.out.print(arv.get(i) + " ");
				retorno.append(arv.get(i) + " ");
				System.out.print("(");
				retorno.append("(");
				fechar++;
			} else {
				System.out.print(arv.get(i) + " ");
				retorno.append(arv.get(i) + " ");
			}
		}
		while (fechar > 0) {
			System.out.print(")");
			retorno.append(")");
			fechar--;
		}
		System.out.println();

		return arvOnlyText;

	}
	
	public static void main(String[] args) {
		Converte converte = new Converte();
		
//		final String queryString = "prefix : <http://www.epimorphics.com/tools/example#>"
//				 + " \nconstruct {"
//				 + " \n:a :P ?v1. ?v1 :Q ?v2."
//				 + " \n:a :P ?v3. ?v3 :R ?v4."
//				 + " \n}"
//				 + " \nwhere{"
//				 + " \n{:a :P ?teste1 OPTIONAL {?v1 :Q ?teste2}}"
//				 + " \nUNION {:a :P ?teste3 OPTIONAL {?v3 :R ?teste4}}" + "\n}";
		String queryString = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX s: <http://www.owl-ontologies.com/sales.owl#>" +  
				"SELECT ?prod ?tit FROM <Sales.owl> WHERE { { {?prod rdf:type s:Music} UNION {?prod rdf:type s:Video} } OPTIONAL {?prod s:title ?tit. ?prod rdf:type s:Video} }";
		
		List<String> testRetorno = converte.processaConsulta(queryString);
		System.out.println(">>>>" + testRetorno + "<<<<");
	}
}
